/**
 * Catalog.java 7 avr. 2006
 * 
 * Copyright (c) 2006 Emmanuel PUYBARET / eTeks <info@eteks.com>. All Rights
 * Reserved.
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 */
package org.windu2b.jcaddie.model;

import java.util.*;

/**
 * Product catalog.
 * 
 * @author Emmanuel Puybaret, windu.2b
 */
public abstract class Catalog
{
	private List<Category>	            categories	       = new ArrayList<Category>();


	private boolean	                    sorted;


	private List<CatalogPieceOfProduct>	selectedProduct	   = new ArrayList<CatalogPieceOfProduct>();


	private List<SelectionListener>	    selectionListeners	= new ArrayList<SelectionListener>();




	/**
	 * Returns the catagories list sorted by name.
	 * 
	 * @return an unmodifiable list of categories.
	 */
	public List<Category> getCategories()
	{
		if ( !sorted )
		{
			Collections.sort( categories );
			sorted = true;
		}
		return Collections.unmodifiableList( categories );
	}




	/**
	 * Adds <code>piece</code> of a given <code>category</code> to this
	 * catalog.
	 * 
	 * @param category
	 *            la <code>Category</code> dans laquelle l'insertion doit se faire
	 * @param product
	 *            Le produit à insérer
	 */
	public void add( Category category, CatalogPieceOfProduct product )
	{
		int index = categories.indexOf( category );
		// If category doesn't exist yet, add it to catagories
		if ( index == -1 )
		{
			add( category );
		}
		else
		{
			category = categories.get( index );
		}
		// Add current piece of product to category list
		category.add( product );
	}




	/**
	 * Adds a category.
	 * 
	 * @param category
	 *            the category to add.
	 * @throws IllegalArgumentException
	 *             if a category with same name as the one in parameter already
	 *             exists in this catalog.
	 */
	private void add( Category category )
	{
		if ( categories.contains( category ) )
		{
			throw new IllegalArgumentException( category.getName()
			        + " already exists in catalog!" );
		}
		categories.add( category );
		sorted = false;
	}




	public String toString()
	{
		String retour = "";

		for ( Category category : categories )
		{
			retour += category + "\n";
		}

		return retour;
	}




	/**
	 * Returns a sub list of <code>items</code> that contains only 
	 * product.
	 */
	public static List<CatalogPieceOfProduct> getProductSubList(
	        List<? extends Object> items )
	{
		return getSubList( items, CatalogPieceOfProduct.class );
	}




	@SuppressWarnings( "unchecked" )
	private static <T> List<T> getSubList( List<? extends Object> items,
	        Class<T> subListClass )
	{
		List<T> subList = new ArrayList<T>();
		for ( Object item : items )
		{
			if ( subListClass.isInstance( item ) )
			{
				subList.add( ( T ) item );
			}
		}
		return subList;
	}




	/**
	 * Returns an unmodifiable list of the selected product in catalog.
	 */
	public List<CatalogPieceOfProduct> getSelectedProduct()
	{
		return Collections.unmodifiableList( selectedProduct );
	}




	/**
	 * Adds the selection <code>listener</code> in parameter to this caddie.
	 */
	public void addSelectionListener( SelectionListener listener )
	{
		selectionListeners.add( listener );
	}




	/**
	 * Removes the selection <code>listener</code> in parameter from this
	 * caddie.
	 */
	public void removeSelectionListener( SelectionListener listener )
	{
		selectionListeners.remove( listener );
	}




	/**
	 * Sets the selected items in caddie and notifies listeners selection change.
	 */
	public void setSelectedProduct( List<CatalogPieceOfProduct> selectedProducts )
	{
		this.selectedProduct = new ArrayList<CatalogPieceOfProduct>(
		        selectedProducts );
		if ( !selectionListeners.isEmpty() )
		{
			SelectionEvent selectionEvent = new SelectionEvent( this,
			        getSelectedProduct() );
			// Work on a copy of selectionListeners to ensure a listener
			// can modify safely listeners list
			SelectionListener[] listeners = selectionListeners
			        .toArray( new SelectionListener[selectionListeners.size()] );

			for ( SelectionListener listener : listeners )
			{
				listener.selectionChanged( selectionEvent );
			}
		}
	}
}